﻿using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using XML_VML.Object;

namespace XML_VML
{
    public class DrawableRect : ContentControl, INotifyPropertyChanged
    {
        public bool IsMoving = true;

        #region TopLeftPoint
        public static readonly DependencyProperty TopLeftPointProperty = DependencyProperty.Register(
                "TopLeftPoint",
                typeof(Point),
                typeof(DrawableRect),
                new FrameworkPropertyMetadata(new Point(), TopLeftPointChanged));

        private static void TopLeftPointChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            var temp = dependencyObject as DrawableRect;
            var newvalue = (Point) eventArgs.NewValue;
            var oldvalue = (Point) eventArgs.OldValue;

            if (temp != null)
            {
                temp.StyleData.Left = newvalue.X;
                temp.StyleData.Top = newvalue.Y;
                if(!temp.IsMoving)
                {
                    temp.StyleData.Width += (oldvalue.X - newvalue.X);
                    temp.StyleData.Height += (oldvalue.Y - newvalue.Y);
                }

                if (temp.StyleData.Width < 30) temp.StyleData.Width = 30;
                if (temp.StyleData.Height < 30) temp.StyleData.Height = 30;

                temp.IsMoving = true;
                temp.GetData().Style = FileManager.GetStringFromStyle(temp.StyleData);
                temp.TopLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top);
                temp.TopRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top);
                temp.BottomLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top + temp.StyleData.Height);
                temp.BottomRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top + temp.StyleData.Height);
                temp.RefreshPoints();
                temp.IsMoving = false;
            }
        }

        public Point TopLeftPoint
        {
            get
            {
                return (Point)GetValue(TopLeftPointProperty);
            }
            set
            {
                SetValue(TopLeftPointProperty, value);
            }
        }
        #endregion

        #region TopRightPoint
        public static readonly DependencyProperty TopRightPointProperty = DependencyProperty.Register(
                "TopRightPoint",
                typeof(Point),
                typeof(DrawableRect),
                new FrameworkPropertyMetadata(new Point(), TopRightPointChanged));

        private static void TopRightPointChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            var temp = dependencyObject as DrawableRect;
            var newvalue = (Point) eventArgs.NewValue;
            var oldvalue = (Point) eventArgs.OldValue;

            if (temp != null)
            { 
                if (newvalue.X - temp.StyleData.Left > 30)
                {
                    temp.StyleData.Width = newvalue.X - temp.StyleData.Left;
                }
                else
                {
                    temp.StyleData.Width = 30;
                }

                if (!temp.IsMoving)
                {
                    temp.StyleData.Top -= (oldvalue.Y - newvalue.Y);
                    temp.StyleData.Height += (oldvalue.Y - newvalue.Y);
                }

                if(temp.StyleData.Height<30) temp.StyleData.Height = 30;

                temp.IsMoving = true;
                temp.GetData().Style = FileManager.GetStringFromStyle(temp.StyleData);
                temp.TopLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top);
                temp.TopRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top);
                temp.BottomLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top + temp.StyleData.Height);
                temp.BottomRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top + temp.StyleData.Height);
                temp.RefreshPoints();
                temp.IsMoving = false;
            }
        }

        public Point TopRightPoint
        {
            get { return (Point)GetValue(TopRightPointProperty); }
            set
            {
                SetValue(TopRightPointProperty, value);
            }
        }
        #endregion

        #region BottomLeftPoint
        public static readonly DependencyProperty BottomLeftPointProperty = DependencyProperty.Register(
                "BottomLeftPoint",
                typeof(Point),
                typeof(DrawableRect),
                new FrameworkPropertyMetadata(new Point(), BottomLeftPointChanged));

        private static void BottomLeftPointChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            var temp = dependencyObject as DrawableRect;
            var newvalue = (Point) eventArgs.NewValue;
            var oldvalue = (Point) eventArgs.OldValue;
            if (temp != null)
            {
                if (newvalue.Y - temp.StyleData.Top > 30)
                {
                    temp.StyleData.Height = newvalue.Y - temp.StyleData.Top;
                }
                else
                {
                    temp.StyleData.Height = 30;
                }

                if (!temp.IsMoving)
                {
                    temp.StyleData.Left -= (oldvalue.X - newvalue.X);
                    temp.StyleData.Width += (oldvalue.X - newvalue.X);
                }

                if (temp.StyleData.Width < 30) temp.StyleData.Width = 30;

                temp.IsMoving = true;
                temp.GetData().Style = FileManager.GetStringFromStyle(temp.StyleData);
                temp.TopLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top);
                temp.TopRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top);
                temp.BottomLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top + temp.StyleData.Height);
                temp.BottomRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top + temp.StyleData.Height);
                temp.RefreshPoints();
                temp.IsMoving = false;
            }
        }

        public Point BottomLeftPoint
        {
            get { return (Point)GetValue(BottomLeftPointProperty); }
            set
            {
                SetValue(BottomLeftPointProperty, value);
            }
        }
        #endregion

        #region BottomRightPoint
        public static readonly DependencyProperty BottomRightPointProperty = DependencyProperty.Register(
                "BottomRightPoint",
                typeof(Point),
                typeof(DrawableRect),
                new FrameworkPropertyMetadata(new Point(), BottomRightPointChanged));

        private static void BottomRightPointChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            var temp = dependencyObject as DrawableRect;
            var newvalue = (Point)eventArgs.NewValue;
            if (temp != null)
            {
                if (newvalue.Y - temp.StyleData.Top > 30)
                {
                    temp.StyleData.Height = newvalue.Y - temp.StyleData.Top;
                }
                else
                {
                    temp.StyleData.Height = 30;
                }

                if (newvalue.X - temp.StyleData.Left > 30)
                {
                    temp.StyleData.Width = newvalue.X - temp.StyleData.Left;
                }
                else
                {
                    temp.StyleData.Width = 30;
                }

                temp.IsMoving = true;
                temp.GetData().Style = FileManager.GetStringFromStyle(temp.StyleData);
                temp.TopLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top);
                temp.TopRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top);
                temp.BottomLeftPoint = new Point(temp.StyleData.Left, temp.StyleData.Top + temp.StyleData.Height);
                temp.BottomRightPoint = new Point(temp.StyleData.Left + temp.StyleData.Width, temp.StyleData.Top + temp.StyleData.Height);
                temp.RefreshPoints();
                temp.IsMoving = false;
            }
        }

        public Point BottomRightPoint
        {
            get { return (Point)GetValue(BottomRightPointProperty); }
            set
            {
                SetValue(BottomRightPointProperty, value);
            }
        }
        #endregion

        #region StrokeColor
        public Color StrokeColor
        {
            get
            {
                if (_data.Stroke)
                {
                    try
                    {
                        var convertFromString = ColorConverter.ConvertFromString(_data.StrokeColor);
                        if (convertFromString != null)
                        {
                            var color = (Color)convertFromString;
                            return color;
                        }
                    }
                    catch (Exception)
                    {
                        return Colors.Black;
                    }
                }
                return Colors.Transparent;
            }
            set { _data.StrokeColor = value.ToString(); }
        }
        #endregion

        #region StrokeWeight

        public float StrokeWeight
        {
            get { return _data.StrokeWeight; }
            set { _data.StrokeWeight = value; }
        }
        #endregion

        #region FillColor
        public Color FillColor
        {
            get
            {
                if (_data.Fill)
                {
                    try
                    {
                        var convertFromString = ColorConverter.ConvertFromString(_data.FillColor);
                        if (convertFromString != null)
                        {
                            var color = (Color)convertFromString;
                            return color;
                        }
                    }
                    catch (Exception)
                    {
                        return Colors.White;
                    }
                }
                return Colors.White;
            }
            set { _data.StrokeColor = value.ToString(); }
        }
        #endregion

        private VRect _data;
        public VStyle StyleData;

        public VRect GetData()
        {
            return _data;
        }

        public void SetData(VRect data)
        {
            _data = data;
            //more
            var style = FileManager.ReadStyleFromString(_data.Style);
            StyleData = style;
            if (StyleData.Width < 0.1)
            {
                StyleData.Width = 100;
            }

            if (StyleData.Height < 0.1)
            {
                StyleData.Height = 100;
            }

            IsMoving = true;
            TopLeftPoint = new Point(StyleData.Left,StyleData.Top);
            TopRightPoint = new Point(StyleData.Left + StyleData.Width, StyleData.Top);
            BottomLeftPoint = new Point(StyleData.Left, StyleData.Top + StyleData.Height);
            BottomRightPoint = new Point(StyleData.Left + StyleData.Width, StyleData.Top + StyleData.Height);
            RefreshPoints();
            IsMoving = false;
        }

        public double CanvasLeft
        {
            get { return StyleData.Left; }
            set { StyleData.Left = value; }
        }

        public double CanvasTop
        {
            get { return StyleData.Top; }
            set { StyleData.Top = value; }
        }

        public double RectWidth
        {
            get { return StyleData.Width; }
            set { StyleData.Width = value; }
        }

        public double RectHeight
        {
            get { return StyleData.Height; }
            set { StyleData.Height = value; }
        }

        public void RefreshPoints()
        {
            OnPropertyChanged("CanvasLeft");
            OnPropertyChanged("CanvasTop");
            OnPropertyChanged("RectWidth");
            OnPropertyChanged("RectHeight");
        }

        static DrawableRect()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawableRect), new FrameworkPropertyMetadata(typeof(DrawableRect)));
        }

        protected bool IsDragging;
        private Point _clickPosition;

        public DrawableRect()
        {
            MouseLeftButtonDown += ControlMouseLeftButtonDown;
            MouseLeftButtonUp += ControlMouseLeftButtonUp;
            MouseMove += ControlMouseMove;
        }

        private void ControlMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            IsDragging = true;
            var draggableControl = sender as Control;
            _clickPosition = e.GetPosition(this);
            if (draggableControl != null) draggableControl.CaptureMouse();
        }

        private void ControlMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            IsDragging = false;
            var draggable = sender as Control;
            if (draggable == null) return;
            var transform = draggable.RenderTransform as TranslateTransform;
            if (transform != null)
            {
                StyleData.Left += transform.Value.OffsetX;
                StyleData.Top += transform.Value.OffsetY;

                IsMoving = true;
                TopLeftPoint = new Point(StyleData.Left, StyleData.Top);
                TopRightPoint = new Point(StyleData.Left + StyleData.Width, StyleData.Top);
                BottomLeftPoint = new Point(StyleData.Left, StyleData.Top + StyleData.Height);
                BottomRightPoint = new Point(StyleData.Left + StyleData.Width, StyleData.Top + StyleData.Height);
                IsMoving = false;
                RefreshPoints();
            }
            draggable.RenderTransform = new TranslateTransform();
            draggable.ReleaseMouseCapture();
        }

        private void ControlMouseMove(object sender, MouseEventArgs e)
        {
            var draggableControl = sender as Control;

            if (!IsDragging || draggableControl == null) return;
            var currentPosition = e.GetPosition(Parent as UIElement);

            var transform = draggableControl.RenderTransform as TranslateTransform;
            if (transform == null)
            {
                transform = new TranslateTransform();
                draggableControl.RenderTransform = transform;
            }

            transform.X = currentPosition.X - _clickPosition.X;
            transform.Y = currentPosition.Y - _clickPosition.Y;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
